#include "Col.ph"
#ifdef __GNUG__
#pragma implementation
#endif

#include "A85Filter.h"
#include "ET_stdio.h"

//---- A85Filter ---------------------------------------------------------------

A85Filter::A85Filter() : StreamBuf()
{
	outbytes= 0;
	phase= 0;
	base256= 0;
	closed= FALSE;
}

//---- A85Encoder --------------------------------------------------------------

A85Encoder::A85Encoder() : A85Filter()
{
	divarray[0]= 1;
	for (int i= 1; i < 5; i++)
		divarray[i]= divarray[i-1]*85;
}

int A85Encoder::Overflow(u_char *bp, int n)
{
	register int i, theChar, index;
		
	for (i= 0; i < n; i++) {
		theChar= bp[i];
		base256+= theChar << (8 * (3 - phase));
		phase++;
				
		if (phase == 4) {
			if (base256) {
				for (index= 4; index >= 0; index--) {
					sb->sputc((int)(base256 / divarray[index] + '!'));
					base256%= divarray[index];
				}
				outbytes+= 5;
				base256= 0;
			} else {
				sb->sputc('z');
				outbytes++;
			}
			phase= 0;
			if (outbytes >= 80) {
				sb->sputc('\n');
				outbytes= 0;
			}
		}
	}
	return i;
}

void A85Encoder::Close()
{
	if (!closed) {
		if (phase > 0) {
			for (int index= 4; index >= (4-phase); index--) {
				sb->sputc((int)(base256 / divarray[index] + '!'));
				base256%= divarray[index];
			}
		}
		sb->sputn("~>", 2);
		closed= TRUE;
	}
}

//---- A85Decoder --------------------------------------------------------------

A85Decoder::A85Decoder() : A85Filter()
{
	eof= 0;
}

void A85Decoder::GetNext()
{
	u_int ccode;
	register int ch;

	if (eof)
		return;
	base256= 0;
	phase= 4;
	for (int cc= 0; cc < 5;) {
		ch= sb->sgetc();
		sb->stossc();
		switch (ch) {
		case '~':
			if (sb->sgetc() != '>')
				break;
			sb->stossc();
		case EOF:
			eof= 1;
			switch (cc) {
			case 1:
				fprintf(stderr, "final partial 5-tuple contains only one character\n");
			case 0:
				phase= 0;
				break;
			default:
				phase= cc-1;
				while (++cc <= 5)
					base256= base256 * 85 + (u_long)0xff;
				break;
			}
			return;
		case 'z':
			if (cc == 0)
				return;
			fprintf(stderr, "z inside 5-tuple\n");
			break;
		case ' ': case '\t': case '\v': case '\n': case '\r': case '\0':
			break;
		default:
			ccode= ch - '!';
			if (ccode < 85) {
				base256= base256 * 85 + ccode;
				cc++;
			}
			break;
		}
	}
}

int A85Decoder::Underflow(u_char *bp, int n)
{
	register u_char *p= bp;

	while (--n >= 0) {
		if (phase == 0) {
			GetNext();
			if (phase == 0)
				return p-bp;
		}
		*p++= (u_char)(base256 >> (8 * (3 - (outbytes++ % 4))));
		phase--;
	}
	return p-bp;
}

